use core_api::db;
use lazy_static::lazy_static;
use std::collections::HashMap;
use std::path::PathBuf;
use std::process::Child;
use std::sync::{Arc, Mutex};
use std::sync::{RwLock, RwLockReadGuard, RwLockWriteGuard};
use tauri_plugin_shell::process::CommandChild;
const STATUS_IS_RECORDING: &str = "isRecording";
pub struct SharedData {
    output_file: Option<PathBuf>,
    ffmpeg_pid: u32,
    ffmpeg: Option<CommandChild>,
    ffmpeg_stop_rx: Option<tokio::sync::mpsc::Receiver<i32>>,
    //detect_device_ready: bool,
    edog: Option<Child>,
    status: Arc<Mutex<HashMap<String, u8>>>,
    hook_status: bool,
    message_manager: Option<db::MessageManager>, // 用于发送消息
}

impl SharedData {
    fn new() -> Self {
        SharedData {
            output_file: None,
            ffmpeg: None,
            ffmpeg_pid: 0,
            ffmpeg_stop_rx: None,
            //detect_device_ready: false,
            edog: None,
            status: Arc::new(Mutex::new(HashMap::new())),
            hook_status: false,
            message_manager: None,
        }
    }

    pub fn get_output_file(&self) -> Option<&PathBuf> {
        self.output_file.as_ref()
    }

    pub fn set_output_file(&mut self, path: PathBuf) {
        self.output_file = Some(path);
    }

    pub fn get_ffmpeg_pid(&self) -> u32 {
        self.ffmpeg_pid
    }

    //https://github.com/tauri-apps/tauri/discussions/3273
    //https://github.com/tauri-apps/tauri/issues/5719
    pub fn stop_ffmpeg(&mut self) -> u32 {
        let pid = self.ffmpeg_pid;
        let pid_file = format!("logs/{}.pid", pid);
        let pid_path = std::path::Path::new(pid_file.as_str());
        let _ = std::fs::remove_file(pid_path);
        pid
    }

    pub fn kill_ffmpeg(&mut self) -> bool {
        //如果进程存在
        if let Some(process) = self.ffmpeg.take() {
            return match process.kill() {
                Ok(()) => {
                    self.ffmpeg_pid = 0;
                    println!("===================kill   recording ok");
                    true
                }
                Err(err) => {
                    println!("===================kill   recording err:{}", err);
                    false
                }
            };
        }
        true
    }

    pub fn set_ffmpeg(&mut self, cc: Option<CommandChild>) {
        if let Some(c) = cc {
            self.ffmpeg.replace(c);
            //设置pid
            self.ffmpeg_pid = self.ffmpeg.as_ref().map_or(0, |p| p.pid());
            self.add_status(STATUS_IS_RECORDING.to_string(), 1);
        } else {
            self.ffmpeg.take();
            self.ffmpeg_pid = 0;
            self.add_status(STATUS_IS_RECORDING.to_string(), 0);
        }
    }

    pub fn set_ffmpeg_stop_rx(&mut self, rx: Option<tokio::sync::mpsc::Receiver<i32>>) {
        if let Some(c) = rx {
            self.ffmpeg_stop_rx.replace(c);
        }
    }

    pub fn get_ffmpeg_stop_rx(&mut self) -> Option<tokio::sync::mpsc::Receiver<i32>> {
        let r = self.ffmpeg_stop_rx.take();
        r
    }

    // pub fn set_detect_device_ready(&mut self, ready: bool) {
    //     self.detect_device_ready = ready;
    // }

    // pub fn get_detect_device_ready(&self) -> bool {
    //     self.detect_device_ready
    // }

    pub fn set_edog(&mut self, cc: Option<Child>) {
        if let Some(c) = cc {
            self.edog.replace(c);
        } else {
            self.edog.take();
        }
    }
    pub fn get_edog(&mut self) -> Option<&mut Child> {
        self.edog.as_mut()
    }

    pub fn stop_edog(&mut self) -> u32 {
        if let Some(mut process) = self.edog.take() {
            let pid = process.id();
            let _ = process.kill();
            self.edog = None;
            pid
        } else {
            0
        }
    }

    pub fn add_status(&mut self, key: String, value: u8) {
        self.status.lock().unwrap().insert(key, value);
    }

    pub fn get_status(&self, key: Option<String>) -> Arc<Mutex<HashMap<String, u8>>> {
        if let Some(k) = key {
            let mut map = HashMap::new();
            if let Some(v) = self.status.lock().unwrap().get(&k) {
                map.insert(k, v.clone());
            }
            Arc::new(Mutex::new(HashMap::new()))
        } else {
            self.status.clone()
        }
    }
    pub fn set_hook_status(&mut self, status: bool) {
        self.hook_status = status;
    }
    pub fn get_hook_status(&self) -> bool {
        self.hook_status
    }

    pub fn set_message_manager(&mut self, mm: Option<db::MessageManager>) {
        if let Some(tx) = mm {
            self.message_manager.replace(tx);
        } else {
            self.message_manager.take();
        }
    }

    pub fn get_message_manager(&self) -> &db::MessageManager {
        self.message_manager.as_ref().unwrap()
    }
}

// unsafe impl Sync for SharedData {}
// 可以使用tauri 状态管理 https://blog.hellagur.com/2022/09/26/%E5%88%9D%E5%A7%8B-Tauri-%E7%AF%87%E5%9B%9B%E4%B9%8B%E7%8A%B6%E6%80%81%E7%AE%A1%E7%90%86/
lazy_static! {
    static ref GLOBAL_DATA: RwLock<SharedData> = RwLock::new(SharedData::new());
}

pub fn write() -> RwLockWriteGuard<'static, SharedData> {
    GLOBAL_DATA.write().unwrap()
}

pub fn read() -> RwLockReadGuard<'static, SharedData> {
    GLOBAL_DATA.read().unwrap()
}
